//  装饰器就是一个方法，可以注入到类，方法，属性参数上来拓展类，属性，方法，参数的功能
//  常见的装饰器有：类装饰器，属性装饰器，方法装饰器，参数装饰器
//  装饰器的写法：普通装饰器（无法传参）装饰器工厂（可传参）


//  类装饰器 普通装饰器
function logClass(param:any){
    //param代表被修饰的类
    console.log(param)
    param.prototype.run = function():void{
        console.log(this.name+'------')
    }
}

@logClass
class HttpClient{
    name:string|undefined
    constructor(name:string|undefined){
        this.name = name
    }
    get(){

    }
}
//  可以使用类为类型 会报错
//  使用any可以不报错
const h:any = new HttpClient('ywj')
h.run()
console.log(HttpClient.prototype)



//  类装饰器 装饰器工厂

function logClass1(param:any):any{
    return function(target:any){
        console.log(target)
        console.log(param)
        target.prototype.url = param
    }
}

@logClass1('hello')
class HttpClient1{
    constructor(){

    }
    get(){

    }
}

const h2:any = new HttpClient1()
console.log(h2.url) 


//类装饰器 重载类

@logClass2
class HttpClient2{
    public name:string | undefined
    constructor(){
        this.name = 'ywj'
    }
    get(){
        console.log('get方法')
    }
}

function logClass2(param:any){
    return class extends param{
        name:any = '修改后的数据'
        get(){
            console.log('修改后的get方法')
        }
        
    }
}

const h3:any = new HttpClient2()
h3.get() 


//  属性装饰器
//  可以给属性添加默认值
class HttpClient3{

    @logProp('ywj')
    public name:string | undefined
    constructor(name:string|undefined){
       this.name = name
    }
    get(){
        console.log(this.name)
    }
}
function logProp(param:any){
    return function(target:any,attr:any){
        console.log(param)
        console.log(target)
        console.log(attr)
        target[attr] = param
    }
}
const h4:any = new HttpClient3('ywjssss')
h4.get()
console.log(h4.name)
console.log(HttpClient3.prototype)

//  方法装饰器
class HttpClient4{
    public url:string|undefined
    constructor(){
        
    }
    @get('hello')
    get(...args:any[]){
        console.log('之前的方法')
    }
}
function get(param:any){
    //  target原型
    //  methodName 方法名
    //  desc方法描述
    //  target可以拓展类 与类装饰器类似
    return function(target:any,methodName:any,desc:any){
        console.log(param)
        console.log(target)
        console.log(methodName)
        console.log(desc)
        //  修改之前的方法
        var oldMethod = desc.value
        desc.value = function(...args:any[]){
            args = args.map((value)=>{
                return String(value)
            })
            console.log(args)
            oldMethod.apply(this,args)
        }
    }
}
const h5:any = new HttpClient4()
h5.get('123',123,false)

//  方法参数装饰器
class HttpClient5{
    constructor(){

    }
    getData(@logParam('123')uuid:any){

    }
}
function logParam(param:any){
    // target原型链
    // method方法名
    // paramIndex参数索引
    // 用来添加类的一些属性和类装饰器类似
    // 使用较少
    return function(target:any,methodName:any,paramIndex:any){
        console.log(param)
        console.log(target)
        console.log(methodName)
        console.log(paramIndex)
    }
}

//  执行顺序 属性》方法》方法参数》类
//  多个同类装饰器 先执行后面的装饰器
